package at.fhooe.swa.client.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Panel;
import java.awt.SystemColor;
import java.awt.TexturePaint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EventObject;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.jfree.chart.plot.dial.DialLayer;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DefaultValueDataset;

import com.toedter.calendar.JCalendar;
import com.toedter.calendar.JDateChooser;

import at.fhooe.swa.client.domain.IBooleanSensor;
import at.fhooe.swa.client.domain.IDoubleSensor;
import at.fhooe.swa.client.domain.ISensor;
import at.fhooe.swa.client.domain.ISensorHistoryData;
import at.fhooe.swa.client.domain.ISensorRegister;
import at.fhooe.swa.client.service.adapter.IServiceAdapter;
import at.fhooe.swa.client.service.adapter.ServiceAdapter;
import at.fhooe.swa.client.service.event.IServiceListener;
import at.fhooe.swa.client.service.event.ServiceHistoryEvent;
import at.fhooe.swa.client.service.event.ServiceTrackEvent;
import at.fhooe.swa.client.util.Resources;

/**
 * Main application Contains the GUI Layout
 * 
 * @author Daniel Karzel
 * 
 */
public class Ems3000Client implements IServiceListener
{
	// frame and content panel
	private JFrame jFrame = null;
	private JPanel jContentPane = null;

	// status bar, top
	private JPanel statusBar = null;
	private JLabel connectionStatus = null;
	private JLabel lastUpdateTime = null;

	// sensor panel center
	private JPanel sensorBar = null;
	Map<String, JPanel> sensorPanels = new HashMap<String, JPanel>();

	// history panel south
	ISensorHistoryData historyData = null;
	private JPanel jHistoryPane = null;
	private JDateChooser jDateFrom = null;
	private JDateChooser jDateTo = null;
	private JComboBox<String> jSensorList = null;
	private String[] sensorList = new String[]
	{ "temperature", "humidity", "smoke", "noise", "lightness" };
	private JButton btnLoadHistory = null;
	private JButton btnPreviewHistory = null;

	// Service Adapter
	private IServiceAdapter adapter;
	
	// test mode
	private boolean test = false;

	private Font theBestFont = new Font("Dialog", Font.BOLD, 14);

	public Ems3000Client()
	{
		adapter = new ServiceAdapter();
		adapter.addListener(this);

		if (!test)
		{
			Thread serviceThread = new Thread(adapter);
			serviceThread.start();
		}

		if (test)
		{
			((ServiceAdapter) adapter).test();
		}
	}

	private JPanel getSensorBar()
	{
		if (sensorBar == null)
		{
			sensorBar = new JPanel();
			sensorBar.setLayout(new WrapLayout());
		}

		return sensorBar;
	}

	private JLabel getConnectionStatus()
	{
		if (connectionStatus == null)
		{
			connectionStatus = new JLabel("not connected");
			connectionStatus.setFont(theBestFont);
		}

		return connectionStatus;
	}

	private JLabel getLastUpdateTime()
	{
		if (lastUpdateTime == null)
		{
			lastUpdateTime = new JLabel("");
			lastUpdateTime.setFont(theBestFont);
		}

		return lastUpdateTime;
	}

	private JPanel getStatusBar()
	{
		if (statusBar == null)
		{
			statusBar = new JPanel();
			statusBar.setLayout(new FlowLayout());

			JLabel labelCon = new JLabel("Connection status: ");
			labelCon.setFont(theBestFont);

			statusBar.add(labelCon);
			statusBar.add(getConnectionStatus());

			JLabel labelTime = new JLabel("; Last update time: ");
			labelTime.setFont(theBestFont);

			statusBar.add(labelTime);
			statusBar.add(getLastUpdateTime());
		}

		return statusBar;
	}

	/**
	 * initializes the content pane
	 * 
	 * @return the content pane (main drawing area)
	 */
	private JPanel getContentPane()
	{
		if (jContentPane == null)
		{
			jContentPane = new JPanel();
			jHistoryPane = new JPanel(new FlowLayout());
			jDateFrom = new JDateChooser();
			// Calendar date = new GregorianCalendar(2013,0,1);
			// jDateFrom.setDate(date.getTime());
			jDateTo = new JDateChooser();
			jSensorList = new JComboBox<String>(sensorList);
			jSensorList.addItemListener(new ItemListener()
			{
				@Override
				public void itemStateChanged(ItemEvent e)
				{
					btnPreviewHistory.setEnabled(false);
				}
			});
			btnLoadHistory = new JButton("Load sensor log");
			btnPreviewHistory = new JButton("View sensor log");
			btnPreviewHistory.setEnabled(false);

			btnLoadHistory.addActionListener(new ActionListener()
			{
				@Override
				public void actionPerformed(ActionEvent e)
				{
					btnPreviewHistory.setEnabled(false);
					Date dateFrom = jDateFrom.getDate();
					Date dateTo = jDateTo.getDate();
					if (dateFrom.after(dateTo))
					{
						JOptionPane.showMessageDialog(jFrame,
								"DateFrom cannot be greater than DateTo!");
					} else
					{
						SimpleDateFormat sdf = new SimpleDateFormat(
								"yyyy-MM-dd HH:mm:ss");
						String dateFromStr = sdf.format(dateFrom);
						String dateToStr = sdf.format(dateTo);

						// retrieve the sensor the data shall be loaded for
						String sensor = jSensorList.getSelectedItem()
								.toString();

						// Request data from the adapter
						adapter.requestTracks(dateFromStr, dateToStr, sensor);
					}
				}
			});
			btnPreviewHistory.addActionListener(new ActionListener()
			{

				@Override
				public void actionPerformed(ActionEvent e)
				{
					HistoryFrame historyWindow = getHistoryPane(historyData);
					historyWindow.setTitle(historyData.getSensor().getDisplayLabel()
							+ " Sensor Log");
					historyWindow.validate();
					historyWindow.pack();
					historyWindow.setVisible(true);
				}
			});

			jHistoryPane.add(jDateFrom);
			jHistoryPane.add(jDateTo);
			jHistoryPane.add(jSensorList);
			jHistoryPane.add(btnLoadHistory);
			jHistoryPane.add(btnPreviewHistory);

			jContentPane.setLayout(new BorderLayout());
			jContentPane.add(getStatusBar(), BorderLayout.NORTH);
			JScrollPane scrollPane = new JScrollPane();
			scrollPane.setViewportView(getSensorBar());
			jContentPane.add(scrollPane, BorderLayout.CENTER);
			jContentPane.add(jHistoryPane, BorderLayout.SOUTH);

		}

		return jContentPane;
	}

	/**
	 * initializes the Java Frame
	 * 
	 * @return the {@link JFrame} object
	 */
	private JFrame getJFrame()
	{
		if (jFrame == null)
		{
			jFrame = new JFrame();
			jFrame.setBackground(SystemColor.controlShadow);

			jFrame.setIconImage(Resources.getIcon("application.icon", null)
					.getImage());
			jFrame.setTitle(Resources.getLabelString("application.title"));

			jFrame.setContentPane(getContentPane());

			// terminate the program once the close button is pressed
			jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		}

		return jFrame;
	}

	private HistoryFrame getHistoryPane(ISensorHistoryData historyData)
	{
		HistoryFrame frame = new HistoryFrame(historyData);
		
//		JPanel panel = new JPanel();
//		panel.setLayout(new GridLayout(rowNum, 2));
//		panel.setSize(new Dimension(300, 150));
//		Map<String, Object> hdata = historyData.getHistoryData();
//		Iterator<Entry<String, Object>> it = hdata.entrySet().iterator();
//		while (it.hasNext())
//		{
//			Entry<String, Object> pairs = (Entry<String, Object>) it.next();
//			panel.add(new JLabel(pairs.getKey()));
//			panel.add(new JLabel(pairs.getValue().toString()));
//		}
//		JScrollPane scrollPane = new JScrollPane(panel);
//		scrollPane
//				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
//		JOptionPane optionPane = new JOptionPane(scrollPane);
		return frame;
	}

	public static void main(String[] args)
	{

		// init GUI and set visible
		UIManager.put("swing.boldMetal", Boolean.FALSE);
		try
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e)
		{
			// nothing to do
		}

		final Ems3000Client application = new Ems3000Client();

		application.getJFrame().validate();
		application.getJFrame().pack();

		// set application window startup size
		application.getJFrame().setSize(800, 800);
		// position application window on screen
		Dimension screen = application.getJFrame().getToolkit().getScreenSize();
		application.getJFrame().setLocation(
				screen.width / 2 - application.getJFrame().getSize().width / 2,
				screen.height / 2 - application.getJFrame().getSize().height
						/ 2);

		// if the application shall start up maximized.
		// application.getJFrame().setExtendedState(Frame.MAXIMIZED_BOTH);

		application.getJFrame().setVisible(true);

		// System.out.println("update sensor...");
		// ((GaugeSensorPanel)application.getTemperaturePanel()).updateDataSet(20.0);
	}

	private void updateGauges(EventObject event)
	{
		if (event instanceof ServiceTrackEvent)
		{
			ISensorRegister register = ((ServiceTrackEvent) event)
					.getRegister();

			getConnectionStatus().setText("Connected! ");
			getLastUpdateTime().setText(register.getLastUpdateTime());

			for (ISensor s : register.getRegisteredSensors())
			{
				// panel for sensor already exists
				if (sensorPanels.get(s.getKey()) != null)
				{
					JPanel sensorPanel = sensorPanels.get(s.getKey());

					if (sensorPanel instanceof GaugeSensorPanel)
					{
						((GaugeSensorPanel) sensorPanel)
								.updateDataSet((Double) s.getCurrentValue());
					} else if (sensorPanel instanceof TextPanel)
					{
						((TextPanel) sensorPanel).updateValue(String.valueOf(s
								.getCurrentValue()));
					}
				}
				// panel for sensor has to be created
				else
				{
					if (s instanceof IDoubleSensor)
					{
						DefaultValueDataset dataset = new DefaultValueDataset(
								(Double) ((IDoubleSensor) s).getCurrentValue());
						JPanel sensorPanel = new GaugeSensorPanel(
								s.getDisplayLabel() + " in " + s.getUnit(),
								s.getDisplayLabel(),
								((IDoubleSensor) s).getMinVal(),
								((IDoubleSensor) s).getMaxVal(), -120, -300,
								10, 5, Color.white, Color.yellow, 0.0, 0.0,
								1.0, 1.0, dataset);
						sensorPanels.put(s.getKey(), sensorPanel);
						getSensorBar().add(sensorPanel);
						// getContentPane().updateUI();
					} else if (s instanceof IBooleanSensor)
					{
						JPanel sensorPanel = new TextPanel(s.getDisplayLabel(),
								s.getUnit(), "false");
						sensorPanels.put(s.getKey(), sensorPanel);
						getSensorBar().add(sensorPanel);
					}
				}
			}

		} else if (event instanceof ServiceHistoryEvent)
		{
			// lala
			// TODO: handle the history stuff...
			historyData = ((ServiceHistoryEvent) event).getHistoryData();
			if (historyData != null)
			{
				btnPreviewHistory.setEnabled(true);
			}
		}
	}

	@Override
	public void handleServiceData(final EventObject event)
	{
		if (EventQueue.isDispatchThread())
			updateGauges(event);
		else
		{
			try
			{
				SwingUtilities.invokeAndWait(new Runnable()
				{

					@Override
					public void run()
					{
						updateGauges(event);
					}
				});
			} catch (InterruptedException e1)
			{
				e1.printStackTrace();
			} catch (InvocationTargetException e1)
			{
				e1.printStackTrace();
			}
		}

	}

}
